package charpter12.lynx;

class BaseballException extends Exception {

	/**
	 * 
	 */
	private static final long serialVersionUID = 3082011818547051609L;
}

class Foul extends BaseballException {

	/**
	 * 
	 */
	private static final long serialVersionUID = -1549603438873686786L;
}

class Strike extends BaseballException {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3014277822352120811L;
}

abstract class Inning {
	public Inning() throws BaseballException {
	}

	public void event() throws BaseballException {
		// Doesn't actually have to throw anything
	}

	public abstract void atBat() throws Strike, Foul;

	public void walk() {
	} // Throws no checked exceptions
}

class StormException extends Exception {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6166298456587830416L;
}

class UmpireArgument extends Exception {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6609804523213253136L;
}

class RainedOut extends StormException {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5345135419960334740L;
}

class PopFoul extends Foul {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5890438029813574219L;
}

interface Storm {
	public void event() throws RainedOut;

	public void rainHard() throws RainedOut;
}

public class Twenty extends Inning implements Storm {
	// OK to add new exceptions for constructors, but you
	// must deal with the base constructor exceptions:
	public Twenty() throws RainedOut, BaseballException {
	}

	public Twenty(String s) throws Foul, BaseballException {
	}

	// Regular methods must conform to base class:
	// ! void walk() throws PopFoul {} //Compile error
	// Interface CANNOT add exceptions to existing
	// methods from the base class:
	// ! public void event() throws RainedOut {}
	// If the method doesn't already exist in the
	// base class, the exception is OK:
	public void rainHard() throws RainedOut {
	}

	// You can choose to not throw any exceptions,
	// even if the base version does:
	public void event() {
	}

	// Overridden methods can throw inherited exceptions:
	public void atBat() throws PopFoul {
	}
	
	public void test() throws UmpireArgument{
	}

	public static void main(String[] args) {
		try {
			Twenty si = new Twenty();
			si.atBat();
			si.test();
		} catch (PopFoul e) {
			System.out.println("Pop foul");
		} catch (RainedOut e) {
			System.out.println("Rained out");
		} catch (BaseballException e) {
			System.out.println("Generic baseball exception");
		} catch (UmpireArgument e) {
			System.out.println("UmpireArgument exception");
		}
		// Strike not thrown in derived version.
		try {
			// What happens if you upcast?
			Inning i = new Twenty();
			i.atBat();
			// You must catch the exceptions from the
			// base-class version of the method:
		} catch (Strike e) {
			System.out.println("Strike");
		} catch (Foul e) {
			System.out.println("Foul");
		} catch (RainedOut e) {
			System.out.println("Rained out");
		} catch (BaseballException e) {
			System.out.println("Generic baseball exception");
		}
	}

}
